#include "command.h"

void print_files_in_dir(void){
    DIR *dir;
    struct dirent *entry;
    struct stat file_stat;

    dir = opendir(".");
    ERROR_CHECK(dir, NULL, "opendir");

    // 遍历目录下的所有文件
    printf("您当前目录下有这些文件: ");
    while ((entry = readdir(dir)) != NULL) {
        // 过滤掉 . 和 ..（仅显示文件）,                                           仅显示普通文件（排除目录）
        if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && stat(entry->d_name, &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
            printf("  %s", entry->d_name);
        }
    }
    printf("\n");

    closedir(dir);

    return;
}

int validate_and_parse_command(int sockfd){
    printf("请输入命令: ");
    char command[1024];
    fgets(command, sizeof(command), stdin);
    command[strlen(command) - 1] = '\0';
    char *p = strtok(command, " ");

    if(get_command_type(p) == CMD_UNKNOWN){
        printf("命令无效\n");
        return -1; // 返回 -1 表示命令无效
    }

    train_t train;
    train.type = get_command_type(p);

    p = strtok(NULL, " "); 

    if (train.type == CMD_CD && !p) {
        char buf[] = "/";   
        train.length = strlen(buf);
        memcpy(train.value, "/", train.length); // 如果cd处理函数这里写了cd ~的情况的话,这里内容也可以发"~"
        send(sockfd, &train, sizeof(train.type) + sizeof(train.length) + train.length, MSG_NOSIGNAL);
        memset(&train, 0, sizeof(train));
        recv(sockfd, &train.type, sizeof(train.type), MSG_WAITALL);
        recv(sockfd, &train.length, sizeof(train.length), MSG_WAITALL);
        recv(sockfd, train.value, train.length, MSG_WAITALL);
        train.value[train.length] = '\0';
        printf("%s\n", train.value);
        return -2; // 返回-2表示命令后面不跟或者没跟内容
    }

    if(train.type == CMD_PWD && !p){ // 无参数指令
        train.length = 0;
        bzero(train.value, sizeof(train.value));
        send(sockfd, &train, sizeof(train.type) + sizeof(train.length) + train.length, MSG_NOSIGNAL);
        recv(sockfd, &train.type, sizeof(train.type), MSG_WAITALL);
        recv(sockfd, &train.length, sizeof(train.length), MSG_WAITALL);
        recv(sockfd, train.value, train.length, MSG_WAITALL);
        train.value[train.length] = '\0';
        printf("%s\n", train.value);
        return -2;
    }

    if(train.type == CMD_EXIT && !p){
        train.length = 0;
        bzero(train.value, sizeof(train.value));
        send(sockfd, &train, sizeof(train.type) + sizeof(train.length) + train.length, MSG_NOSIGNAL);
        exit(0);
    }


    if(!p){
        train.length = 0;
        bzero(train.value, sizeof(train.value));
        send(sockfd, &train, sizeof(train.type) + sizeof(train.length) + train.length, MSG_NOSIGNAL);
        memset(&train, 0, sizeof(train));

        recv(sockfd, &train.type, sizeof(train.type), MSG_WAITALL);
        recv(sockfd, &train.length, sizeof(train.length), MSG_WAITALL);
        recv(sockfd, train.value, train.length, MSG_WAITALL);
        train.value[train.length] = '\0';
        printf("%s\n", train.value);
        return -2;
    }

    train.length = strlen(p);
    memset(train.value, 0, sizeof(train.value));
    memcpy(train.value, p, train.length);
    send(sockfd, &train, sizeof(train.type) + sizeof(train.length) + train.length, MSG_NOSIGNAL);
    if(train.type == CMD_PUTS){
        sendFile(train.value, sockfd);
    }
    if(train.type == CMD_GETS){
        recvFile(sockfd);
    }

    memset(&train, 0, sizeof(train));
    recv(sockfd, &train.type, sizeof(train.type), MSG_WAITALL);
    recv(sockfd, &train.length, sizeof(train.length), MSG_WAITALL);
    recv(sockfd, train.value, train.length, MSG_WAITALL);
    train.value[train.length] = '\0';
    printf("%s\n", train.value);


    return 0;
}

CommandType get_command_type(const char* input) {
    if (strcmp(input, "cd") == 0) return CMD_CD;
    if (strcmp(input, "ls") == 0) return CMD_LS;
    if (strcmp(input, "pwd") == 0) return CMD_PWD;
    if (strcmp(input, "puts") == 0) return CMD_PUTS;
    if (strcmp(input, "gets") == 0) return CMD_GETS;
    if (strcmp(input, "mkdir") == 0) return CMD_MKDIR;
    if (strcmp(input, "rmdir") == 0) return CMD_RMDIR;
    if (strcmp(input, "exit") == 0) return CMD_EXIT;
    if (strcmp(input, "rm") == 0) return CMD_RM; 

    return CMD_UNKNOWN; // 默认返回未知命令
}

// // 处理文件:客户端读取本地文件 → 按协议封装数据 → 发送给服务端
// // 客户端输入(puts fileName)文件上传命令---服务端进行文件下载---怎么存到路径?pwd路径拼接再存?
// int cmd_puts(char *fileName, int sockfd){
//     int file_fd = open(fileName, O_RDONLY);
//     ERROR_CHECK(file_fd, -1, "open");

//     train_t train;
//     memset(&train, 0,sizeof(train_t));
//     // 发送1：先发文件名: 5 + "file1" :发送文件吗这一步是不是已经做好了
//     train.length = strlen(fileName);// 放火车头，比如file1--train.length = 5 size_t类型
//     memcpy(train.value, fileName, train.length);// 放车厢,train.value = "file1"
//     send(sockfd, &train.length, sizeof(train.length), 0);// 发送火车头：四个字节（5）
//     send(sockfd, train.value, train.length,0);// 发车厢：发送"file1"
//     // 发送2：再发文件大小
//     struct stat statbuf;// 获取文件信息
//     fstat(file_fd, &statbuf);
//     off_t filesize = statbuf.st_size;// 获得文件大小,比如1mb,off_t决定是8个字节
//     printf("filesize = %ld\n", filesize);
//     train.length = sizeof(filesize);
//     memcpy(train.value, &filesize, train.length);
//     send(sockfd, &train.length, sizeof(train.length), MSG_NOSIGNAL);// 收方收到4个字节，得知后续文件是一个8字节数据
//     send(sockfd, train.value, train.length, MSG_NOSIGNAL);// 再发文件本身大小:8个字节;收方收到8字节数据，解析出文件大小1mb字节
//     // 发送3：文件内容
//     sendfile(sockfd,file_fd,NULL,filesize);// 0拷贝技术，底层是mmap映射
//     close(file_fd);
//     return 0;
// }

// static int recvn(int sockfd, void *buf, int length){
//     int total = 0;
//     char *p = (char *)buf;
//     while(total < length){
//         // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//         // 第二位是buf,这里p+total 利用了char只有一个字节+ 指针偏移
//         ssize_t sret = recv(sockfd, p+total, length-total, 0);
//         total += sret;
//     }
//     return 0;
// }

// //客户端接收服务端发送的文件信息 → 在本地创建文件 → 写入接收的数据
// // 客户端输入(gets fileName)文件下载指令---服务端进行文件上传
// int cmd_gets(int sockfd){
//     // 从main.c调用函数可以看出，参数是sockfd,
//     // 建立连接本质就是客户端的sockfd和服务端的netfd连接
//     train_t train;
//     // 第一轮 发送文件这部分已经做好了吧
//     char fileName[4096] = {0};
//     recv(sockfd, &train.length,sizeof(int),MSG_WAITALL);// 收火车头
//     recv(sockfd, train.value,train.length,MSG_WAITALL);// 收车厢
//     memcpy(fileName, train.value, train.length);
//     int file_fd = open(fileName,O_RDWR |O_CREAT|O_TRUNC,0666);

//     off_t filesize;
//     recvn(sockfd, &train.length, sizeof(train.length));
//     recvn(sockfd, train.value, train.length);
//     memcpy(&filesize, train.value, train.length);
//     printf("filesize = %ld\n", filesize);

//     // 那就要考虑内存问题
//     ftruncate(file_fd, filesize);
//     char *p = (char *)mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, file_fd, 0);
//     recvn(sockfd, p, filesize);
//     munmap(p, filesize);
//     close(file_fd);
//     return 0;
// }


//by wwh
int recvFile(int socket_fb){  //客户端和cmd_gets对应
    train_t train;
    memset(&train,0,sizeof(train));
    recv(socket_fb,&train.length,sizeof(train.length),MSG_WAITALL);
    recv(socket_fb,train.value,train.length,MSG_WAITALL);
    printf("fileName==%s\n",train.value);
    int file_fb=open(train.value,O_RDWR|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(file_fb,-1,"open");
    off_t filesize;
    recv(socket_fb,&train.length,sizeof(train.length),MSG_WAITALL);
    recv(socket_fb,&filesize,train.length,MSG_WAITALL);
    printf("filesize==%ld\n",filesize);
    bzero(&train,sizeof(train));
    off_t total=0;
    while(1){
        printf("%5.2lf%%\r",100.0*total/filesize);
        fflush(stdout);
        recv(socket_fb,&train.length,sizeof(train.length),MSG_WAITALL);
        //if(total==filesize){
        //    printf("recv over\n");
        //    break;
        //}
        if(total==filesize){
            printf("recv over\n");
            break;
        }
        total+=train.length;
        recv(socket_fb,train.value,train.length,MSG_WAITALL);//如果是最后的车头为0的时，接收会阻塞吗
        write(file_fb,train.value,train.length);
        bzero(train.value,train.length);
    }
    printf("100.00%%\n");
    return 0;
}

int sendFile(char* fileName,int netfb){//客户端和cmd_puts对应

    int file_fb=open(fileName,O_RDWR);//这个文件名是命令里切出来的
    ERROR_CHECK(file_fb,-1,"open");
    train_t train;
    //  train.length=strlen(fileName);
    //  memcpy(train.value,fileName,strlen(fileName));
    //  send(netfb,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    //  send(netfb,train.value,train.length,MSG_NOSIGNAL);//客户端不发文件名
    struct stat statbuf;                                                                                                                                                                                   
    fstat(file_fb,&statbuf);
    off_t filesize=statbuf.st_size;
    train.length=sizeof(filesize);
    memcpy(train.value,&filesize,sizeof(filesize));
    send(netfb,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netfb,train.value,train.length,MSG_NOSIGNAL);//发文件大小
    while(1){//发文件内容
        int ret=read(file_fb,train.value,sizeof(train.value));
        send(netfb,&ret,sizeof(train.length),MSG_NOSIGNAL);
        /* send(netfb,train.value,ret,MSG_NOSIGNAL);//放在这里为什么不像之前一样卡住呢 */
        send(netfb,train.value,ret,MSG_NOSIGNAL);
        if(ret==0){
            printf("send over\n");
            break;
        }
    }
    close(file_fb);
    return 0;
}
